package com.jsh.erp;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
@Component
public class AuthFilter implements GlobalFilter {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private AuthProperties authProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        String method = request.getMethodValue();
        String token = request.getHeaders().getFirst("X-Access-Token");
        String toPath = request.getHeaders().getFirst("X-To-Path");
        if(log.isDebugEnabled()) {
            log.debug("{},{},{},{}", method, path, toPath, token);
        }
        //  白名单放行
        if(authProperties.getWhiteList().contains(path)) {
            log.info("{}匹配了白名单，直接放行", path, authProperties.getWhiteList());
            return chain.filter(exchange);
        }
        //  token检查
        if(!StringUtils.hasText(token)) {
            log.warn("{}没有token，禁止访问", path);
        }
        //  根据token从redis取出用户的权限列表，验证是否有权限
        if(hasPerms(token, toPath)) {
            log.info("{}匹配了权限列表，直接放行", path);
            return chain.filter(exchange);
        }
        log.warn("{}禁止访问", path);
        return unAuth(exchange, HttpStatus.FORBIDDEN, "无权访问");
    }

    private boolean hasPerms(String token, String toPath) {
        String funcList = (String) stringRedisTemplate.opsForHash().get(token, "funcList");
        if(log.isDebugEnabled()) {
            log.debug("funcList:{}", funcList);
        }
        if(!StringUtils.hasText(funcList)) {
            return false;
        }
        Set<String> funcSet = new HashSet<>(Arrays.asList(funcList.split(",")));
        funcSet.add("/dashboard/analysis");
        return funcSet.contains(toPath);
    }

    @SneakyThrows
    private Mono<Void> unAuth(ServerWebExchange exchange, HttpStatus status, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(status);
        response.getHeaders().set(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
        Map<String, Object> result = new HashMap<>();
        result.put("code", status.value());
        result.put("msg", message);
        String json = new ObjectMapper().writeValueAsString(result);
        return response.writeWith(Mono.just(response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8))));
    }
}
